﻿using System;
using System.Data;
using System.Linq;
using DataScripter.Database;

namespace DataScripter.Scripting.Query.SqlServer
{
    public class DataProducer : IDataProducer
    {
        private Db Db { get; set; }

        public DataProducer(Db db)
        {
            Db = db;
        }

        public IDataReader ProduceData(ITableScriptRequest tableScriptRequest)
        {
            string query = ProduceQuery(tableScriptRequest);
            return Db.ExecuteReader(query);
        }

        public IDataReader ProduceRelatedData(ITableScriptRequest tableScriptRequest, IDataReader parentRecord, ITableScriptRequest parentTable)
        {
            string query = ProduceRelatedQuery(tableScriptRequest, parentRecord, parentTable);
            return Db.ExecuteReader(query);
        }

        private string ProduceRelatedQuery(ITableScriptRequest tableScriptRequest, IDataReader parentRecord,
                                           ITableScriptRequest parentTable)
        {
            IForeignKey fkToUse = DetermineForeignKeyToUse(tableScriptRequest, parentTable);

            if (fkToUse == null)
                throw new ArgumentException("Cannot find foreign key", "tableScriptRequest");

            string parentColumnName = fkToUse.ReferencedTableName == tableScriptRequest.TableName
                                          ? fkToUse.ColumnName
                                          : fkToUse.ReferencedColumnName;
            string childColumnName = fkToUse.ReferencedTableName == tableScriptRequest.TableName
                                         ? fkToUse.ReferencedColumnName
                                         : fkToUse.ColumnName;
            FieldInfo parentField = parentTable.TableStructure.Fields[parentColumnName];

            return ProduceQuery(tableScriptRequest) + " AND " + childColumnName + "=" + parentField.ReadValue(parentRecord);
        }

        private static IForeignKey DetermineForeignKeyToUse(ITableScriptRequest tableScriptRequest,
                                                            ITableScriptRequest parentTable)
        {
            foreach (IForeignKey foreignKey in parentTable.TableStructure.ForeignKeys)
            {
                if (foreignKey.ReferencedTableName == tableScriptRequest.TableName)
                {
                    return foreignKey;
                }
            }
            return tableScriptRequest.TableStructure.ForeignKeys.FirstOrDefault(foreignKey => foreignKey.ReferencedTableName == parentTable.TableName);
        }

        public string ProduceQuery(ITableScriptRequest tableScriptRequest)
        {
            string fullWhereClause = tableScriptRequest.ProduceWhereClause();
            string query = "SELECT * FROM " + tableScriptRequest.TableName + fullWhereClause;
            tableScriptRequest.UsedQuery = query;
            return query;
        }
    }
}
